diff options
Diffstat (limited to 'app/[lng]')
3 files changed, 250 insertions, 0 deletions
diff --git a/app/[lng]/evcp/(evcp)/general-contract-template/[id]/not-found.tsx b/app/[lng]/evcp/(evcp)/general-contract-template/[id]/not-found.tsx new file mode 100644 index 00000000..01dfb6a3 --- /dev/null +++ b/app/[lng]/evcp/(evcp)/general-contract-template/[id]/not-found.tsx @@ -0,0 +1,22 @@ +import Link from "next/link" +import { Button } from "@/components/ui/button" +import { ArrowLeft } from "lucide-react" + +export default function NotFound() { + return ( + <div className="container mx-auto py-6"> + <div className="flex flex-col items-center justify-center space-y-4 text-center"> + <h1 className="text-2xl font-bold">템플릿을 찾을 수 없습니다</h1> + <p className="text-muted-foreground"> + 요청하신 일반계약 템플릿이 존재하지 않거나 삭제되었습니다. + </p> + <Link href="/evcp/general-contract-template"> + <Button variant="outline" className="flex items-center gap-2"> + <ArrowLeft className="h-4 w-4" /> + 목록으로 돌아가기 + </Button> + </Link> + </div> + </div> + ) +}
\ No newline at end of file diff --git a/app/[lng]/evcp/(evcp)/general-contract-template/[id]/page.tsx b/app/[lng]/evcp/(evcp)/general-contract-template/[id]/page.tsx new file mode 100644 index 00000000..897ba46c --- /dev/null +++ b/app/[lng]/evcp/(evcp)/general-contract-template/[id]/page.tsx @@ -0,0 +1,154 @@ +import * as React from "react" +import { notFound } from "next/navigation" +import { ArrowLeft, FileText, Download, Edit } from "lucide-react" +import Link from "next/link" +import { Metadata } from "next" + +import { Button } from "@/components/ui/button" +import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@/components/ui/card" +import { Badge } from "@/components/ui/badge" +import { formatDateTime } from "@/lib/utils" +import { getContractTemplateById } from "@/lib/general-contract-template/service" +import { TemplateEditorWrapper } from "@/lib/general-contract-template/template/template-editor-wrapper" + +interface GeneralContractTemplateDetailPageProps { + params: Promise<{ id: string; lng: string }> +} + +// 메타데이터 생성 +export async function generateMetadata({ + params +}: GeneralContractTemplateDetailPageProps): Promise<Metadata> { + const resolvedParams = await params + const template = await getContractTemplateById(parseInt(resolvedParams.id)); + + if (!template) { + return { + title: "템플릿을 찾을 수 없음", + description: "요청한 일반계약 템플릿을 찾을 수 없습니다." + }; + } + + return { + title: `${template.contractTemplateName} (v${template.revision}) - 일반계약 템플릿`, + description: `${template.contractTemplateName} 템플릿의 상세 정보 및 편집 페이지입니다.` + }; +} + +export default async function GeneralContractTemplateDetailPage({ + params +}: GeneralContractTemplateDetailPageProps) { + const resolvedParams = await params + const { id, lng } = resolvedParams + + // ID가 숫자인지 확인 + const templateId = parseInt(id) + if (isNaN(templateId)) { + notFound() + } + + // 템플릿 데이터 조회 + const template = await getContractTemplateById(templateId) + if (!template) { + notFound() + } + + // 페이지 새로고침 서버 액션 + const handleRefresh = async () => { + "use server" + // refreshTemplatePage 함수가 필요하면 추가 + }; + + return ( + <div className="container mx-auto py-6 space-y-6"> + {/* Header */} + <div className="flex items-center justify-between"> + <div className="flex items-center space-x-4"> + <Link href={`/${lng}/evcp/general-contract-template`}> + <Button variant="outline" size="sm"> + <ArrowLeft className="mr-2 h-4 w-4" /> + 목록으로 + </Button> + </Link> + <div> + <h1 className="text-2xl font-bold flex items-center"> + <FileText className="mr-2 h-6 w-6 text-blue-500" /> + {template.contractTemplateName} + <Badge variant="outline" className="ml-2"> + v{template.revision} + </Badge> + </h1> + <p className="text-muted-foreground"> + 일반계약 템플릿 상세 정보 및 편집 + </p> + </div> + </div> + + <div className="flex items-center space-x-2"> + {/* DownloadButton 등 필요한 경우 추가 */} + </div> + </div> + + <div className="space-y-4"> + {/* 상단 - 기본 정보만 (최대한 압축) */} + <Card> + <CardHeader className="pb-2"> + <CardTitle className="text-sm">기본 정보</CardTitle> + </CardHeader> + <CardContent className="py-2"> + <div className="flex items-center space-x-6"> + <div className="flex items-center space-x-2"> + <label className="text-xs font-medium text-muted-foreground">상태:</label> + <Badge variant={template.status === "ACTIVE" ? "default" : template.status === "DISPOSED" ? "destructive" : "secondary"} className="text-xs h-5"> + {template.status === "ACTIVE" ? "활성" : template.status === "DISPOSED" ? "폐기" : "비활성"} + </Badge> + </div> + + <div className="flex items-center space-x-2"> + <label className="text-xs font-medium text-muted-foreground">버전:</label> + <span className="text-xs font-medium">v{template.revision}</span> + </div> + + <div className="flex items-center space-x-2"> + <label className="text-xs font-medium text-muted-foreground">법무검토:</label> + <Badge variant={template.legalReviewRequired ? "destructive" : "secondary"} className="text-xs h-5"> + {template.legalReviewRequired ? "필요" : "불필요"} + </Badge> + </div> + + <div className="flex items-center space-x-2"> + <label className="text-xs font-medium text-muted-foreground">파일:</label> + <span className="text-xs">{template.fileName || "파일 없음"}</span> + </div> + </div> + </CardContent> + </Card> + + {/* 하단 - 파일 뷰어 (전체 너비, 높이 증가) */} + <Card className="h-[950px]"> + <CardHeader className="pb-2"> + <div className="flex items-center justify-between"> + <div> + <CardTitle className="text-lg flex items-center"> + <Edit className="mr-2 h-5 w-5 text-blue-500" /> + 템플릿 편집기 + </CardTitle> + <CardDescription className="text-sm"> + Word 문서를 편집하고 {'{{변수}}'} 를 설정할 수 있습니다. + </CardDescription> + </div> + </div> + </CardHeader> + <CardContent className="h-[calc(100%-80px)] p-0"> + <TemplateEditorWrapper + templateId={template.id} + filePath={template.filePath} + fileName={template.fileName} + refreshAction={handleRefresh} + /> + </CardContent> + </Card> + </div> + </div> + ); +}
\ No newline at end of file diff --git a/app/[lng]/evcp/(evcp)/general-contract-template/page.tsx b/app/[lng]/evcp/(evcp)/general-contract-template/page.tsx new file mode 100644 index 00000000..8a652690 --- /dev/null +++ b/app/[lng]/evcp/(evcp)/general-contract-template/page.tsx @@ -0,0 +1,74 @@ +import * as React from "react" +import { type SearchParams } from "@/types/table" + +import { getValidFilters } from "@/lib/data-table" +import { Skeleton } from "@/components/ui/skeleton" +import { DataTableSkeleton } from "@/components/data-table/data-table-skeleton" +import { Shell } from "@/components/shell" +import { getContractTemplates } from "@/lib/general-contract-template/service" +import { searchParamsTemplatesCache } from "@/lib/general-contract-template/validations" +import { ContractTemplateTable } from "@/lib/general-contract-template/template/general-contract-template" +import { InformationButton } from "@/components/information/information-button" + +interface IndexPageProps { + searchParams: Promise<SearchParams> +} + +export default async function IndexPage(props: IndexPageProps) { + const searchParams = await props.searchParams + const search = searchParamsTemplatesCache.parse(searchParams) + + const validFilters = getValidFilters(search.filters) + + const promises = Promise.all([ + getContractTemplates({ + ...search, + filters: validFilters, + }), + ]) + + return ( + <Shell className="gap-2"> + <div className="flex items-center justify-between space-y-2"> + <div className="flex items-center justify-between space-y-2"> + <div> + <div className="flex items-center gap-2"> + <h2 className="text-2xl font-bold tracking-tight"> + 일반계약(Contract) 표준양식 관리 + </h2> + <InformationButton pagePath="evcp/general-contract-template" /> + </div> + <p className="text-muted-foreground mt-2"> + 다양한 계약 유형의 표준양식을 관리합니다. LO, FA, PO, CS, EU 등 계약 종류별 템플릿을 등록하고 편집할 수 있습니다. + </p> + </div> + </div> + + </div> + + <React.Suspense fallback={<Skeleton className="h-7 w-52" />}> + {/* 필요시 날짜 범위 선택기 추가 */} + {/* <DateRangePicker + triggerSize="sm" + triggerClassName="ml-auto w-56 sm:w-60" + align="end" + shallow={false} + /> */} + </React.Suspense> + + <React.Suspense + fallback={ + <DataTableSkeleton + columnCount={10} + searchableColumnCount={2} + filterableColumnCount={4} + cellWidths={["4rem", "6rem", "6rem", "8rem", "20rem", "6rem", "6rem", "8rem", "8rem", "6rem", "6rem", "6rem"]} + shrinkZero + /> + } + > + <ContractTemplateTable promises={promises} /> + </React.Suspense> + </Shell> + ) +} |
